/*!
 * \file ems_core.h
 *
 * \brief TIBCO EMS模块主文件
 *
 * All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.
 *
 * \version 1.0
 * \author songbb
 * \date 2016/10/24
 *
 */

#ifndef __EMS_CORE_H_
#define __EMS_CORE_H_

#include "frlist.h"
#include "frhash2.h"
#include "frstr.h"

#include "conntrack.h"
#include "module.h"
#include "frbyte_buffer.h"

/*! @brief 常用包类型 */
typedef enum __em_ems_pkt_type {
    EMS_PKT_TYPE_NONE = 0,
    EMS_PKT_TYPE_BYTES_MSG,
    EMS_PKT_TYPE_STREAM_MSG,
    EMS_PKT_TYPE_TEXT_MSG,
    EMS_PKT_TYPE_OBJECT_MSG,
    EMS_PKT_TYPE_MAP_MSG,
    EMS_PKT_TYPE_DATA_MSG = 6,
    EMS_PKT_TYPE_CONFIRM = 9,
    EMS_PKT_TYPE_RESPONSE_OK,
    EMS_PKT_TYPE_RESPONSE_ERR,
    EMS_PKT_TYPE_INIT_CONNECTION,
    EMS_PKT_TYPE_DESTROY_CONNECTION,
    EMS_PKT_TYPE_START_CONNECTION,
    EMS_PKT_TYPE_STOP_CONNECTION,
    EMS_PKT_TYPE_INIT_SESSION,
    EMS_PKT_TYPE_DESTROY_SESSION,
    EMS_PKT_TYPE_RECOVER_SESSION,
    EMS_PKT_TYPE_COMMIT_SESSION,
    EMS_PKT_TYPE_ROLLBACK_SESSION,
    EMS_PKT_TYPE_INIT_CONSUMER,
    EMS_PKT_TYPE_DESTROY_CONSUMER,
    EMS_PKT_TYPE_INIT_PRODUCER,
    EMS_PKT_TYPE_DESTROY_PRODUCER,
    EMS_PKT_TYPE_UNSUBSCRIBE_CONSUMER,
    EMS_PKT_TYPE_START_CONSUMER = 27,
    EMS_PKT_TYPE_STOP_CONSUMER,
    EMS_PKT_TYPE_RID_FLOW_REQUEST,
    EMS_PKT_TYPE_FLOW_REQUEST,
    EMS_PKT_TYPE_FLOW_RESPONSE,
    EMS_PKT_TYPE_INIT_BROWSER,
    EMS_PKT_TYPE_DESTROY_BROWSER,
    EMS_PKT_TYPE_BROWSER_RETRIEVE,
    EMS_PKT_TYPE_TMP_DEST_DESTROY,
    EMS_PKT_TYPE_PURGE_RECORD,
    EMS_PKT_TYPE_SET_CLIENTID,
    EMS_PKT_TYPE_TMP_DEST_CREATE = 45,
    EMS_PKT_TYPE_SSL_RENEGOTIATE_PREREQUEST = 55,
    EMS_PKT_TYPE_SSL_RENEGOTIATE_REQUEST,
    EMS_PKT_TYPE_SSL_RENEGOTIATE_PROCEED,
    EMS_PKT_TYPE_SSL_RESET_TO_TCP,
    EMS_PKT_TYPE_FT_INFO = 70,
    EMS_PKT_TYPE_XA_RECOVER = 80,
    EMS_PKT_TYPE_XA_START,
    EMS_PKT_TYPE_XA_END,
    EMS_PKT_TYPE_XA_PREPARE,
    EMS_PKT_TYPE_XA_COMMIT,
    EMS_PKT_TYPE_XA_ROLLBACK,
    EMS_PKT_TYPE_ASYNC_CLIENT_CMD = 88,
    EMS_PKT_TYPE_RECOVER_MSG = 105,
    EMS_PKT_TYPE_RECOVER_CONSUMER_MSG,
    EMS_PKT_TYPE_MDAEMON_INIT_CONNECTION = 110,
    EMS_PKT_TYPE_MDAEMON_CONNECTION_DESTROY,
    EMS_PKT_TYPE_MDAEMON_CONNECTION_START,
    EMS_PKT_TYPE_MDAEMON_CONNECTION_STOP,
    EMS_PKT_TYPE_MDAEMON_CONSUMER_START,
    EMS_PKT_TYPE_MDAEMON_CONSUMER_STOP,
    EMS_PKT_TYPE_MDAEMON_CONSUMER_INIT,
    EMS_PKT_TYPE_MDAEMON_CONSUMER_DESTROY,
    EMS_PKT_TYPE_MDAEMON_STATS,
    EMS_PKT_TYPE_ASYNC_MDAEMON_CMD,
    EMS_PKT_TYPE_MULTICAST_CLIENT_NOTIFY,
    EMS_PKT_TYPE_MULTICAST_CONFIG,
    EMS_PKT_TYPE_MULTICAST_CONFIG_REQUEST,
    EMS_PKT_TYPE_MULTICAST_CLIENT_STATUS,
    EMS_PKT_TYPE_MULTICAST_DAEMON_STATUS,
    EMS_PKT_TYPE_LAST_TYPE = 127
} Ems_pkt_type;

typedef enum __em_ems_section_type {
    EMS_SECTION_TYPE_UNKNOWN = 0,
    EMS_SECTION_TYPE_HEADER = 22,
    EMS_SECTION_TYPE_PROPERTIES,
    EMS_SECTION_TYPE_BODY,
    EMS_SECTION_TYPE_DESTIDS,
    EMS_SECTION_TYPE_SEQ,
} Ems_section_type;

typedef enum __em_ems_object_type {
    EMS_OBJECT_TYPE_NULL = 0,
    EMS_OBJECT_TYPE_BOOL,
    EMS_OBJECT_TYPE_BYTE,
    EMS_OBJECT_TYPE_WCHAR,
    EMS_OBJECT_TYPE_SHORT,
    EMS_OBJECT_TYPE_INT,
    EMS_OBJECT_TYPE_LONG,
    EMS_OBJECT_TYPE_FLOAT,
    EMS_OBJECT_TYPE_DOUBLE,
    EMS_OBJECT_TYPE_UTF8,
    EMS_OBJECT_TYPE_BYTES,
    EMS_OBJECT_TYPE_SUBMAP,
    EMS_OBJECT_TYPE_SHORTA_ARRAY,
    EMS_OBJECT_TYPE_INT_ARRAY,
    EMS_OBJECT_TYPE_LONG_ARRAY,
    EMS_OBJECT_TYPE_FLOAT_ARRAY,
    EMS_OBJECT_TYPE_DOUBLE_ARRAY,
    EMS_OBJECT_TYPE_VARLONG,
    EMS_OBJECT_TYPE_SUBSTREAM,
} Ems_object_type;

typedef struct __st_ems_object
{
    Ems_object_type type;
    union {
        char c_bool;
        char c_byte;
        short s_wchar;
        short s_short;
        int i_int;
        long long ll_long;
        float f_float;
        double d_double;
        char *p_utf8;
        long long ll_varlong;
    } value;
} Ems_object;

/*! @brief TIBCO EMS 生产者/消费者模型 */
typedef enum __em_ems_model_type {
    EMS_MODEL_TYPE_UNKNOWN = 0,
    EMS_MODEL_TYPE_CONSUMER,
    EMS_MODEL_TYPE_PRODUCER,
} Ems_model_type;

/*! @brief TIBCO EMS协议通用包头 */
typedef struct __st_ems_header
{
    unsigned int ui_header_len;         //!< 消息头长度 - 到全局事务超时时间为止
    unsigned int ui_pkt_len;            //!< 消息体长度(包含消息头)
    Ems_pkt_type pkt_type;              //!< 数据包类型
    Ems_model_type model_type;          //!< 通信模型
} Ems_header;

/*! @brief L7session_te 用于存放TIBCO EMS私有的session数据，对应L7_session的p_session_private变量 */
typedef struct __st_L7session_ems
{
    Ems_model_type model_type;          //!< 通信模型
    char *p_encoding;                   //!< 编码
} L7session_ems;

/*! @brief 分片的状态 */
typedef enum __em_fragment_state {
    APM_EMS_FRAGMENT_INIT,                     //!< 初始化
    APM_EMS_FRAGMENT_NEED_NEXT_REQ_PACKET,     //!< 需要下一个请求包
    APM_EMS_FRAGMENT_NEED_NEXT_RESP_PACKET     //!< 需要下一个响应包
} Ems_fragment_state;

/*! @brief TIBCO EMS数据包 */
typedef struct __st_L7_ems_packet
{
    Ems_header st_ems_header;               //!< 包头
    Ems_fragment_state fragment_state;      //!< 当前的分片状态
    Frbyte_Packet *p_st_packet;             //!< 组包完成的数据
    unsigned int ui_len_to_read;            //!< 还需要从下一个payload中读取多少个字节
    struct timeval st_timestamp_first;      //!< 第一个请求的分片包的时间
    struct timeval st_timestamp_last;       //!< 最后一个请求的分片包的时间
    int i_is_req;                           //!< 是否是请求包
} L7_ems_packet;

/*! @brief TIBCO EMS私有结构体 */
typedef struct __st_L7session_ems_private
{
    L7session_ems *p_st_sess;                //!< session数据
    L7_ems_packet *p_st_ems_packet;          //!< 当前处理中的TIBCO EMS数据包
    L7_session *p_st_session;                //!< 指向父级的L7_session结构体
    Frlist_header *p_report_comm;            //!< 用于临时存储report的公共部分数据
    Frlist_header *p_report_req;             //!< 用于临时存储report的请求部分数据
    struct timeval st_req_end_timestamp;     //!< 请求的结束时间戳
} L7session_ems_private;

/*!
 * 判断当前数据链路是否是TIBCO EMS协议的
 *
 * \param p_st_conn        (ct信息)
 * \param p_st_packet      (协议分析入力数据)
 *
 * \return 参照module.h中APM_L7_IS_的定义
 *
 */
int ems_detect(Conntrack *p_st_conn
                , Apm_packet *p_st_packet);

/*!
 * TIBCO EMS协议解析入口
 *
 * \param p_st_conn             (ct信息)
 * \param p_st_packet           (协议分析入力数据)
 * \param p_st_hash_report      (保存Frreport_data)
 *
 * \return 参照module.h中APM_L7_ANALYZE_的定义
 *
 */
int ems_analyze(Conntrack *p_st_conn
                , Apm_packet *p_st_packet
                , Frhash_header *p_st_hash_report);

/*!
 * 释放TIBCO EMS private数据
 *
 * \param p_st_session_privaems_in        (TIBCO EMS的私有信息)
 *
 * \return 0  失败\n
 *         1  成功
 *
 */
int ems_session_destory(void *p_st_session_privaems_in);

#endif
